﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.IO;
using System.Collections;

namespace Fsb.Utility
{
    public class HttpUtility
    {
        public static string UrlEncode(string str, Encoding encoding)
        {
            if (string.IsNullOrEmpty(str)) return string.Empty;

            StringBuilder sb = new StringBuilder();
            byte[] byStr = encoding.GetBytes(str); //默认是System.Text.Encoding.Default.GetBytes(str)
            for (int i = 0; i < byStr.Length; i++)
            {
                sb.Append(@"%" + Convert.ToString(byStr[i], 16));
            }

            return (sb.ToString());
        }

        public static string UrlDecode(string url, Encoding encoding)
        {
            if (string.IsNullOrEmpty(url)) return string.Empty;

            int length = url.Length;
            UrlDecoder decoder = new UrlDecoder(length, encoding);
            for (int i = 0; i < length; i++)
            {
                char ch = url[i];
                if (ch == '+')
                {
                    ch = ' ';
                }
                else if ((ch == '%') && (i < (length - 2)))
                {
                    if ((url[i + 1] == 'u') && (i < (length - 5)))
                    {
                        int num3 = HexToInt(url[i + 2]);
                        int num4 = HexToInt(url[i + 3]);
                        int num5 = HexToInt(url[i + 4]);
                        int num6 = HexToInt(url[i + 5]);
                        if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0)))
                        {
                            goto Label_0106;
                        }
                        ch = (char)((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6);
                        i += 5;
                        decoder.AddChar(ch);
                        continue;
                    }
                    int num7 = HexToInt(url[i + 1]);
                    int num8 = HexToInt(url[i + 2]);
                    if ((num7 >= 0) && (num8 >= 0))
                    {
                        byte b = (byte)((num7 << 4) | num8);
                        i += 2;
                        decoder.AddByte(b);
                        continue;
                    }
                }
            Label_0106:
                if ((ch & 0xff80) == 0)
                {
                    decoder.AddByte((byte)ch);
                }
                else
                {
                    decoder.AddChar(ch);
                }
            }
            return decoder.GetString();

        }

        public static string Get(string url)
        {
            return Get(url, Encoding.UTF8);
        }

        public static string Get(string url, Encoding encoding)
        {
            WebClient wc = new WebClient();
            byte[] data = wc.DownloadData(new Uri(url));

            return encoding.GetString(data);
        }

        public static string Post(string url)
        {
            CookieContainer cookieContainer = new CookieContainer();
            return Post(url, ref cookieContainer);
        }

        public static string Post(string url, NameValueCollection postData)
        {
            CookieContainer cookieContainer = new CookieContainer();
            return Post(url, null, postData, ref cookieContainer);
        }

        public static string Post(string url, ref CookieContainer cookieContainer)
        {
            return Post(url, null, ref cookieContainer);
        }

        public static string Post(string url, string userAgent, ref CookieContainer cookieContainer)
        {
            return Post(url, userAgent, ref cookieContainer);
        }

        public static string Post(string url, string userAgent, NameValueCollection postData, ref CookieContainer cookieContainer)
        {
            return Post(url, userAgent, postData, Encoding.UTF8, ref cookieContainer);
        }

        public static string Post(string url, string userAgent, NameValueCollection postData, Encoding encoding, ref CookieContainer cookieContainer)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "POST";
            request.Proxy = null;
            request.UserAgent = userAgent;
            request.ContentType = "application/x-www-form-urlencoded";

            request.CookieContainer = cookieContainer;

            string data = string.Empty;
            if (postData != null && postData.Count > 0)
            {
                foreach (string key in postData.AllKeys)
                {
                    if (!string.IsNullOrEmpty(data))
                    {
                        data += "&";
                    }
                    data += key + "=" + postData[key];
                }
            }

            byte[] buffer = encoding.GetBytes(data);
            request.ContentLength = buffer.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(buffer, 0, buffer.Length);
                requestStream.Close();
            }

            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    using (StreamReader sr = new StreamReader(response.GetResponseStream(), encoding))
                    {
                        return sr.ReadToEnd();
                    }
                }
                else
                {
                    throw new WebException("远程服务器错误的应答。");
                }
            }
        }

        private static int HexToInt(char h)
        {
            if ((h >= '0') && (h <= '9'))
            {
                return (h - '0');
            }
            if ((h >= 'a') && (h <= 'f'))
            {
                return ((h - 'a') + 10);
            }
            if ((h >= 'A') && (h <= 'F'))
            {
                return ((h - 'A') + 10);
            }
            return -1;
        }
    }

    class UrlDecoder
    {
        // Fields
        private int _bufferSize;
        private byte[] _byteBuffer;
        private char[] _charBuffer;
        private Encoding _encoding;
        private int _numBytes;
        private int _numChars;

        // Methods
        public UrlDecoder(int bufferSize, Encoding encoding)
        {
            this._bufferSize = bufferSize;
            this._encoding = encoding;
            this._charBuffer = new char[bufferSize];

        }

        internal void AddByte(byte b)
        {
            if (this._byteBuffer == null)
            {
                this._byteBuffer = new byte[this._bufferSize];
            }
            this._byteBuffer[this._numBytes++] = b;
        }

        internal void AddChar(char ch)
        {
            if (this._numBytes > 0)
            {
                this.FlushBytes();
            }
            this._charBuffer[this._numChars++] = ch;
        }

        private void FlushBytes()
        {
            if (this._numBytes > 0)
            {
                this._numChars += this._encoding.GetChars(this._byteBuffer, 0, this._numBytes, this._charBuffer, this._numChars);
                this._numBytes = 0;
            }
        }

        internal string GetString()
        {
            if (this._numBytes > 0)
            {
                this.FlushBytes();
            }
            if (this._numChars > 0)
            {
                return new string(this._charBuffer, 0, this._numChars);
            }
            return string.Empty;

        }
    }
}
